package com.example.socketdemo.nio.two;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

public class Server {
    // 客户端通道
    private ServerSocketChannel ssChannel;
    // 客户端选择器
    private Selector selector;
    // 监听端口
    private static final int PORT = 9999;

    public Server(){
        try {
            // 1. 获取选择器
            selector = Selector.open();
            // 2. 获取通道
            ssChannel = ServerSocketChannel.open();
            // 3. 修改非阻塞模式
            ssChannel.configureBlocking(false);
            // 4. 绑定端口
            ssChannel.bind(new InetSocketAddress(PORT));
            // 5. 注册选择器
            ssChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void listener() {

        try {
            while(selector.select() > 0){
                // 获取就绪监听事件
                Iterator<SelectionKey> it = selector.selectedKeys().iterator();
                // 便利事件
                while(it.hasNext()){
                    SelectionKey sk = it.next();

                    if(sk.isAcceptable()){
                        // 获取客户端socketChannel
                        SocketChannel schannel = ssChannel.accept();
                        // 修改阻塞状态
                        schannel.configureBlocking(false);
                        // 注册选择器
                        schannel.register(selector, SelectionKey.OP_READ);

                    }else if(sk.isReadable()){
                        //处理读 (专门写方法..)
                        readData(sk);
                    }

                    it.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    //读取客户端消息
    private void readData(SelectionKey sk) {
        SocketChannel schannel = null;
        try {
            // 获取客户端通道
            schannel = (SocketChannel) sk.channel();
            
            ByteBuffer buf = ByteBuffer.allocate(1024);
            int read = schannel.read(buf);

            if(read > 0){
                buf.flip();
                String msg = new String(buf.array(), 0, buf.remaining());
                System.out.println(msg);
                //向其它的客户端转发消息(去掉自己), 专门写一个方法来处理
                sendInfoToOtherClients(msg, schannel);
            }

        } catch (Exception e) {

            try {
                System.out.println(schannel.getRemoteAddress() + " 离线了..");
                sk.cancel();
                schannel.close();
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }


    }

    private void sendInfoToOtherClients(String msg, SocketChannel schannel) throws IOException {
        System.out.println("服务器转发消息中...");
        System.out.println("服务器转发数据给客户端线程: " + Thread.currentThread().getName());

        for (SelectionKey selectedKey : selector.keys()) {
            Channel  channel = selectedKey.channel();

            if(channel instanceof  SocketChannel && channel != schannel){
                ByteBuffer buf = ByteBuffer.wrap(msg.getBytes());
                //buf.flip();
                ((SocketChannel) channel).write(buf);
            }

        }
    }

    public static void main(String[] args) {

        Server server = new Server();
        server.listener();

    }


}
